const arrayProto = Array.prototype;

// 对数组的代理，本质上是对数组方法的代理
function defArrayFunc(obj, func, namespace, vm) {
    Object.defineProperty(obj, func, {
        enumerable: true, //可枚举
        configurable: true, //可配置
        value: function (...args) {
            let original = arrayProto[func];
            const result = original.apply(this, args);
            console.log(getNameSpace(namespace, ''))
            return result;
        }
    })
}

function proxyArr(vm, arr, namespace) {
    let obj = {
        eleType: 'Array',
        toString: function () {
            let result = "";
            for (let i = 0; i < arr.length; i++) {
                result = arr[i] + ', '
            }
            return result.substring(0, result.length - 2)
        },
        push() {},
        pop() {},
        shift() {},
        unshift() {}
    }
    defArrayFunc.call(vm, obj, 'push', namespace, vm);
    defArrayFunc.call(vm, obj, 'pop', namespace, vm);
    defArrayFunc.call(vm, obj, 'shift', namespace, vm);
    defArrayFunc.call(vm, obj, 'unshift', namespace, vm);
    arr.__proto__ = obj;
    return arr;
}

function constructObjectProxy(vm, obj, namespace) {
    let proxyObj = {};
    for (let prop in obj) {
        Object.defineProperty(proxyObj, prop, {
            configurable: true,
            get() {
                return obj[prop];
            },
            set: function (value) {
                obj[prop] = value;
            }
        })
        Object.defineProperty(vm, prop, {
            configurable: true,
            get() {
                return obj[prop]
            },
            set: function (value) {
                obj[prop] = value;
            }
        })
        if (obj[prop] instanceof Object) {
            proxyObj[prop] = constructProxy(vm, obj[prop], getNameSpace(namespace, prop))
        }
    }
    return proxyObj;
}

// 我们要知道那个属性被修改了，这样我们才能根据修改对页面上的内容进行更行
// 我们必须先捕获修改的这个事件
// 所以我们需要用代理的方式来实现监听属性修改
export function constructProxy(vm, obj, namespace) { //vm:表示FVue对象，obj表示要进行代理的对象，namespace
    let proxyObj = null
    if (obj instanceof Array) {
        proxyObj = new Array(obj.length);
        for (let i = 0; i < obj.length; i++) {
            proxyObj[i] = constructProxy(vm, obj[i], namespace)
        }
        proxyObj = proxyArr(vm, obj, namespace)
    } else if (obj instanceof Object) {
        proxyObj = constructObjectProxy(vm, obj, namespace);
    } else {
        throw new Error('error')
    }
    return proxyObj;
}

function getNameSpace(nowNameSapce, nowProps) {
    if (nowNameSapce == null || nowNameSapce == "") {
        return nowProps;
    } else if (nowProps == null || nowProps == "") {
        return nowNameSapce;
    } else {
        return nowNameSapce + '.' + nowProps;
    }
}